#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>

#include <linux/gpio.h>
#include <plat/gpio-cfg.h>


#define DRIVER_NAME "hello_kernel_platform_driver_device"
#define MISC_CHAR_DEVICE_NAME "hello_kernel_misc"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Bruce.zc_wang");

enum
{
	LED2=1,
	LED3=33,
	OTHER
};

enum
{
	OFF,
	ON
};

static int hello_kernel_misc_dev_open(struct inode *inode, struct file *files)
{ 
	printk(KERN_EMERG "hello kernel misc dev open\n");
	return 0;
}

static int hello_kernel_misc_dev_release(struct inode *inode, struct file *files)
{
	printk(KERN_EMERG "hello kernel misc dev relese\n");
	return 0;
}

static long hello_kernel_misc_dev_ioctl(struct file *files, unsigned int cmd, unsigned long arg)
{
	printk(KERN_EMERG "cmd is %d, arg is %d\n", cmd, arg);
	switch(cmd)
	{
		case LED2:
			if(arg != 0 && arg != 1)
			{
				printk(KERN_EMERG "invalid arguments\n");
				return -1;
			}
			else
			{
				if(arg == 0)
				{
					printk(KERN_EMERG "Turn off LED2\n");
				}
				else
				{
					printk(KERN_EMERG "Turn on LED2\n");

				}
				gpio_set_value(EXYNOS4_GPL2(0), arg);
			}
			break;
		case LED3:
			if(arg != 0 && arg != 1)
			{
				printk(KERN_EMERG "invalid arguments\n");
				return -1;
			}
			else
			{
				if(arg == 0)
				{
					printk(KERN_EMERG "Turn off LED3\n");
				}
				else
				{
					printk(KERN_EMERG "Turn on LED3\n");

				}
				gpio_set_value(EXYNOS4_GPK1(1), arg);
			}
			break;

		default:
			printk(KERN_EMERG "invalid command!!!\n");
			return -1;
	}
	
	return 0;
}

static struct file_operations hello_kernel_misc_dev_ops = {
	.owner = THIS_MODULE,
	.open = hello_kernel_misc_dev_open,
	.release = hello_kernel_misc_dev_release,
	.unlocked_ioctl = hello_kernel_misc_dev_ioctl,
};

static struct miscdevice hello_kernel_misc_dev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = MISC_CHAR_DEVICE_NAME,
	.fops = &hello_kernel_misc_dev_ops,
};

static int hello_kernel_probe(struct platform_device *pdv)
{
	int ret;
	printk(KERN_EMERG "\t initialized hello kernel driver\n");
	ret = gpio_request(EXYNOS4_GPL2(0), "LED2");
	if(ret < 0) {
		printk(KERN_EMERG "GPIO request LED2 EXYNOS4_GPL2(0) failed\n");
		return ret;
	}
	s3c_gpio_cfgpin(EXYNOS4_GPL2(0), S3C_GPIO_OUTPUT);
	gpio_set_value(EXYNOS4_GPL2(0), 0);


	ret = gpio_request(EXYNOS4_GPK1(1), "LED3");
	if(ret < 0) {
		printk(KERN_EMERG "GPIO request LED3 EXYNOS4_GPK1(1) failed\n");
		return ret;
	}
	s3c_gpio_cfgpin(EXYNOS4_GPK1(1), S3C_GPIO_OUTPUT);
	gpio_set_value(EXYNOS4_GPK1(1), 0);

	misc_register(&hello_kernel_misc_dev);

	return 0;
}
static int hello_kernel_remove(struct platform_device *device)
{
	printk(KERN_EMERG "\tremove\n");
	misc_deregister(&hello_kernel_misc_dev);
	return 0;
}
static void hello_kernel_shutdown(struct platform_device *device)
{
}
static int hello_kernel_suspend(struct platform_device *device, pm_message_t state)
{
	return 0;
}
static int hello_kernel_resume(struct platform_device *device)
{
	return 0;
}


struct platform_driver hello_kernel_driver = {
	.probe = hello_kernel_probe,
	.remove = hello_kernel_remove,
	.shutdown = hello_kernel_shutdown,
	.suspend = hello_kernel_suspend,
	.resume = hello_kernel_resume,
	.driver = {
		.name = DRIVER_NAME,
		.owner = THIS_MODULE,
	}
};

static int hello_kernel_init(void)
{
	int driver_state;
	printk(KERN_EMERG "++++++Hello kernel Enter++++++\n");
	driver_state = platform_driver_register(&hello_kernel_driver);
	printk(KERN_EMERG "\tdriver state is %d\n", driver_state);
	return 0;
}

static void hello_kernel_exit(void)
{
	printk(KERN_EMERG "------hello kernel driver exit------\n");
	platform_driver_unregister(&hello_kernel_driver);
}

module_init(hello_kernel_init);
module_exit(hello_kernel_exit)
